#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <cstl/common.h>
#include <cstl/memory_manager.h>
#include <cstl/memory_pool.h>

/**
* Global memory pool object.
*/
mempool_t GMempool = 0;

/**
* Check whether the GMempool is initialized.
*/
#define MEMMANAGER_CHECK() \
    do {\
        if (!GMempool)\
        {\
            fprintf(stderr, "fault: memmanger block have not been initializ or have exited!\n");\
            exit(1);\
        }\
    } while(0)

/**
* Create and Init global memory pool
*/
bool memmanager_init()
{
    // PRINT_FUN();
    if (!GMempool)
    {
        mempool_init(&GMempool);
    }

    if (GMempool)
    {
        return true;
    }
    else
    {
        return false;
    }
}

/**
* Destroy global memory pool
*/
void memmanager_exit()
{
    if (GMempool)
    {
        mempool_destroy(&GMempool);
        GMempool = 0;
    }

    if (__memoryleak)
    {
        fprintf(stderr, "warnning: memory leak detected and the leak nums is %d!\n", __memoryleak);
    }
}

/**
* Allocate memory through memory pool.
*/
void* cstl_malloc(unsigned int size)
{
    if (!GMempool)
    {
        memmanager_init();
    }
    // if (!cstl_init()) exit()
    // PRINT_FUN();
    // cstl_init();


    // MEMMANAGER_CHECK();

    /*
    uint32* ret = (uint32*)mempool_malloc(GMempool, size + 4);
    if (ret)
    {
        *ret = size + 4;
    }
    return (ret + 1);
    */
    uint32* ret = (uint32*)mempool_malloc(GMempool, size);

    /*
    if (ret)
    {
        printf("cstl_malloc: size is %d\n", malloc_usable_size(ret));
    }
    */
    return ret;
}

/**
* Free memory through memory pool.
*/
void cstl_free(void* mem)
{
    // cstl_init();

    if (0 == GMempool)
    {
        memmanager_init();
    }

    // MEMMANAGER_CHECK();

    uint32 size = 0;
    // uint32* raw = 0;
    /*
    if (mem)
    {
        raw = ((uint32*)mem) - 1;
        size = *raw;
        // printf("size is %d\n", size);
        mempool_free(GMempool, raw, size);
    }
    */
    if (mem)
    {
        size = malloc_usable_size(mem);
        // printf("cstl_free: size is %d\n", size);
        mempool_free(GMempool, mem, size);
    }
}

/**
* Allocate memory and set memory content to zero through memory pool.
*/
void* cstl_calloc(unsigned int size)
{
    void* ret = 0;
    ret = cstl_malloc(size);
    if (ret)
    {
        memset(ret, 0, size);
    }
    return ret;
}

/**
* Dealloc
* @param oldmem
* @param size
* @return
*/
void* cstl_realloc(void* oldmem, unsigned int size)
{

        return realloc(oldmem, size);
}

/**
* Get real size allocated.
*/
size_t cstl_malloc_size(void* mem)
{
    return malloc_usable_size(mem);
}

/**
* Get the memory leaks.
*/
size_t cstl_memory_leak()
{
    return __sys_leak_num();
}

